﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DynaPrecision.Financial
{
	/// <summary>
	/// 
	/// </summary>
	public class TransformedFiniteDifferenceScheme : OptionPricingDataHolder
	{
		public virtual void Initiate()
		{
			_priceList = new List<double>();
			_transformedPriceList = new List<double>();
			for (int i = 0; i < this.TransformedPriceDivisionCount + 1; i++)
			{
				_transformedPriceList.Add(this.TransformedPriceAtIndex(i));
				_priceList.Add(DeTransformPrice(this._transformedPriceList.Last()));
			}
		}
		#region Payoff and Boundary Values
		public IInitialAndBoundaryValueProvider _initialAandBoundaryValueProvider;
		public IInitialAndBoundaryValueProvider InitialAndBoundaryValueProvider
		{
			get
			{
				return _initialAandBoundaryValueProvider;
			}
			set
			{
				_initialAandBoundaryValueProvider = value;
				_initialAandBoundaryValueProvider.DataHolder = this as OptionPricingDataHolder;
			}
		}
		#endregion

		#region Common Coefficients
		public virtual double TimePriceSquaredDivisionRatio
		{
			get
			{
				return TransformedTimeDivision / TransformedPriceDivision / TransformedPriceDivision;
			}
		}
		public virtual double ValueTransformMultiplier(double transformedPrice, double transformedTime)
		{
			return BaseLinePrice * Math.Exp(-0.5 * (PriceTransformCoefficientWithYield - 1) * transformedPrice - (0.25 * (PriceTransformCoefficientWithYield - 1) * (PriceTransformCoefficientWithYield - 1) + PriceTransformCoefficientNoYield) * transformedTime);
		}
		public virtual double PriceTransformCoefficientNoYield
		{
			get
			{
				return 2 * RiskFreeInterestRate / Volatility / Volatility;
			}
			set
			{
				throw new NotSupportedException("Transform Coefficient K doesn't support edit here in " + this.GetType().Name);
			}
		}
		public virtual double PriceTransformCoefficientWithYield
		{
			get
			{
				return 2 * (RiskFreeInterestRate - ContinuousYieldRate) / Volatility / Volatility;
			}
			set
			{
				throw new NotSupportedException();
			}
		}
	
		#endregion

		#region Price And Transformed Price
		public virtual double PriceLowerBound
		{
			get
			{
				return DeTransformPrice(TransformedPriceLowerBound);
			}
			set
			{
				throw new NotSupportedException();
			}
		}
		public virtual double PriceUpperBound
		{
			get
			{
				return DeTransformPrice(TransformedPriceUpperBound);
			}
			set
			{
				throw new NotSupportedException();
			}
		}
		public virtual double TransformedPriceAtIndex(int i)
		{
			return TransformedPriceLowerBound + i * TransformedPriceDivision;
		}
		public virtual double TransformPrice(double Price)
		{
			return Math.Log(Price / BaseLinePrice);
		}
		public virtual double DeTransformPrice(double transformedPrice)
		{
			return BaseLinePrice * Math.Exp(transformedPrice);
		}
		public virtual double BaseLinePrice
		{
			get
			{
				return this.StrikePrice;
			}
			set
			{
				this.StrikePrice = value;
			}
		}
		public virtual double TransformedPriceUpperBound
		{
			get;
			set;
		}
		public virtual double TransformedPriceLowerBound
		{
			get;
			set;
		}
		public virtual double TransformedPriceDivision
		{
			get
			{
				return (TransformedPriceUpperBound - TransformedPriceLowerBound) / TransformedPriceDivisionCount;
			}
			set
			{
				throw new NotSupportedException("Transformed Price Division doesn't support edit here " + this.GetType().Name);
			}
		}
		public virtual int TransformedPriceDivisionCount
		{
			get;
			set;
		}

		protected IList<double> _priceList = null;
		protected IList<double> _transformedPriceList = null;
		#endregion
		
		#region Time and Transformed Time
		public virtual double TransformedTimeAtIndex(int i)
		{
			return TransformedTimeDivision * i;
		}
		public virtual double TransformTime(double time)
		{
			return (Expiration - time) * 0.5 * Volatility * Volatility;
		}
		public virtual double DeTransformTime(double transformedTime)
		{
			return Expiration - transformedTime * 2 / Volatility / Volatility;
		}
		public virtual double TransformedTimeDivision
		{
			get
			{
				return (this.TransformedExpiration) / TransformedTimeDivisionCount;
			}
			set
			{
				throw new NotSupportedException("Transformed Time Division doesn't support edit here in " + this.GetType().Name);
			}
		}
		public virtual int TransformedTimeDivisionCount
		{
			get;
			set;
		}
		public virtual double TransformedExpiration
		{
			get
			{
				return Volatility * Volatility * 0.5 * Expiration;
			}
			set
			{
				throw new NotSupportedException("Transformed Expiration tau doesn't support edit here in " + this.GetType().Name);
			}
		}
		#endregion
	}
}